完整範例請看:http://wcc723.github.io/d3js/2014/10/24/Ironman-30-days-25/
上一篇介紹了資料的來源以及動機,這篇就來介紹執行的層面吧。
在原本的範例中,是只有一個圓在跳動,但是音樂所能擷取的資料是一段很長的陣列,我就思考著是不是有辦法做成折線圖,並且讓他有躍動的感覺。
音樂來源:http://unlimited.kptaipei.tw/
範例參考:http://webfinal.herokuapp.com/slides.html
先看一下HTML的結構,在左邊呈現圖像化的效果,右邊是柯P的音樂選單,重要的是下方的class="controller",這並不是js的套件或是code,僅僅是Chrome的html5物件。
<div class="demo">
<div class="player">
<div class="visual">
</div>
<div class="playlist">
</div>
<div class="controller">
</div>
</div>
</div>
直接透過d3.json去接柯P的資料,之前有提過KP這方面處理得相當好,用d3.js就可以直接接資料,接回來的範例如下,也可以直接打開chrome console看更完整資料。
d3.json(kpMusic, function(data){ //取得柯P音樂資料
console.log(data.data)
dataMusic = data.data; //存到dataMusic
playlist() //執行下一個function
});
這一段是特別需要注意的,因為音樂的所傳回的陣列長度是2048,值大概像下面這樣,範圍由-1 ~ 1,也因為長度過長,在繪製成圖形上會有效能上的問題,所以擷取其中一段即可。
所以該段js大概像這樣:
//buffer 為傳來的值
newBuffer = Array.prototype.slice.call(buffer,0,64)
//由於來源陣列長度有2048,這邊只取64就好
var xScale = d3.scale.linear().domain([0, newBuffer.length]).range([0, w]);
var yScale = d3.scale.linear().domain([1, -1]).range([h, 0]);
//先前有提到資料最大及最小就是-1 ~ 1,輸出範圍就是曲線跳動的最大範圍
var line = d3.svg.line()
.x(function(d,i) {
return xScale(i + 1); //利用尺度運算資料索引,傳回x的位置
})
.y(function(d) {
return yScale(d); //利用尺度運算資料的值,傳回y的位置
});
path.attr('d', line(newBuffer)); //將音樂資料套用至曲線
完整範例請看:http://wcc723.github.io/d3js/2014/10/24/Ironman-30-days-25/
很抱歉,目前本範例只支援Chrome
如果有興趣想要跟著實驗,只要把這段貼回家就可以玩囉
var kpMusic = 'http://api.kptaipei.tw/v1/musics/1?accessToken=kp54103aa1efbe14.85567715'
//柯p資料路徑
var dataMusic = ""; //音樂資料
var colorBase = 0; //圓圈的顏色起始
var context; //音樂格式
var h = 100, w = 300;
d3.json(kpMusic, function(data){ //取得柯P音樂資料
console.log(data.data)
dataMusic = data.data; //存到dataMusic
playlist() //執行下一個function
});
//這部分是建立基本的layout
var svg = d3.select(".visual").append('svg')
.attr({
width: 300,
height: 300
});
//畫面中的圓圈
circle = svg.append('circle')
.attr({
cx: 150,
cy: 150
});
//播放中音樂的文字
playtext = svg.append('text')
.attr({
x: 20,
y: 20,
width: 260,
fill: "white"
})
//中央跳動的曲線
rect = svg.append('g')//增加一個群組g
.attr('width', w)
.attr('height', h)
.attr('transform', 'translate(0,' + (h) + ')');
path = rect.append('path')
var audio = new Audio(); //建立音樂
function playlist(){
d3.select(".playlist").selectAll("a").data(dataMusic) //右方先插入歌單
.enter()
.append("a")
.text(function(d){ return d.song_name }) //傳入音樂名稱
.attr("class", "song"); //插入Class,作為控制用
audio.controls = true; //html5 音樂控制器
audio.preload = true; //html5 預先下載
document.querySelector('.controller').appendChild(audio);
//指定部分插入html5 audio元件
d3.selectAll(".song").on("click", function(d){
playsong(d); //點擊歌單時載入音樂
});
}
//瀏覽器驗證
try
{
context = new webkitAudioContext();
}
catch(e)
{
try
{
context= new AudioContext();
}
catch(e)
{
}
}
function processAudio(e) { //如果音樂開始執行時
//取得音軌資訊
var buffer = e.inputBuffer.getChannelData(0);
var out = e.outputBuffer.getChannelData(0);
var amp = 0;
// Iterate through buffer to get max amplitude
for (var i = 0; i < buffer.length; i++) {
var loud = Math.abs(buffer[i]);
if(loud > amp) {
amp = loud;
}
// write input samples to output unchanged
out[i] = buffer[i];
};
newBuffer = Array.prototype.slice.call(buffer,0,64)
//由於來源陣列長度有2048,這邊只取64就好
var xScale = d3.scale.linear().domain([0, newBuffer.length]).range([0, w]);
var yScale = d3.scale.linear().domain([1, -1]).range([h, 0]);
//先前有提到資料最大及最小就是-1 ~ 1,輸出範圍就是曲線跳動的最大範圍
var line = d3.svg.line()
.x(function(d,i) {
return xScale(i + 1); //利用尺度運算資料索引,傳回x的位置
})
.y(function(d) {
return yScale(d); //利用尺度運算資料的值,傳回y的位置
});
colorBase ++; //讓顏色隨著時間變化
var color = d3.hsl(colorBase % 360, .7,.7); //d3.hsl色彩運算
circle.attr("r",20+(amp*50)) //圓圈大小變換,以及顏色變換
.attr("fill", color)
.attr("stroke", color);
path.attr('d', line(newBuffer)); //將音樂資料套用至曲線
}
//以下為音樂相關的code
var node = context.createMediaElementSource(audio);
var processor = context.createScriptProcessor(2048,1,1);
function playsong(d){
console.log(d)
audio.src = d.stream_url;
playtext.text(d.song_name + ' / ' + d.groupname)
audio.addEventListener('canplaythrough',function() {
processor.onaudioprocess = processAudio;
node.connect(processor);
processor.connect(context.destination);
});
}
還有CSS要補上喔~
.player {
background-color: #000;
width: 540px;
padding: 20px;
border-radius: 2px;
}
.player circle{
fill: none;
}
path {
stroke: DodgerBlue;
fill: none;
}
.visual{
float: left;
}
.playlist{
float: right;
width: 200px;
height: 300px;
overflow-y: auto;
}
.playlist a{
color: white;
display: block;
cursor: pointer;
}
.playlist a.selected {
color: DeepSkyBlue;
}
.controller{
clear: both;
}
鐵人賽快要結束了,不過我到快結束才更了解D3js,有很多豐富的技巧還沒介紹的說...。